Skip to content

Conversation

@kagol
Copy link
Member

@kagol kagol commented Dec 31, 2025

PR

主要更新:

  • 引入 @opentiny/next-sdk / @opentiny/next-remoter,并接入 WebAgent 服务,用于实现智能化,可通过自然语言,让AI帮助人完成添加词条、添加菜单等操作
  • 增加 MCP 工具:添加词条(add-i18n-entry)、添加菜单(add-menu

效果如下:

添加词条:

AI添加词条

添加菜单:

AI添加菜单

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Remote agent UI added for interactive sessions.
    • Remote command/server tools to automate adding locales and menus.
    • Programmatic method to populate menu form state.
  • Bug Fixes

    • Fixed CSS syntax and improved global z-index styling.
  • Chores

    • Added runtime dependencies to support remote agent and SDK functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

Walkthrough

Adds MCP integration to the TinyVue template: pins a top-level override, adds remoter/sdk deps, wires a message-channel transport and WebMcpClient in App.vue, registers WebMcpServer tools in locale/menu components, adds a sleep util, minor style fix, and a setMenuInfo API.

Changes

Cohort / File(s) Summary
Top-level config
package.json
Added pnpm overrides entry for @modelcontextprotocol/sdk -> 1.16.0.
TinyVue template deps
template/tinyvue/package.json
Added dependencies: @opentiny/next-remoter ^0.0.10, @opentiny/next-sdk ^0.1.15.
App — MCP client & transport
template/tinyvue/src/App.vue
Creates message-channel pair transport, instantiates WebMcpClient with clientTransport, connects as agent (fixed sessionId and URL), and provides serverTransport to children.
Feature components — MCP server tools
template/tinyvue/src/views/locale/components/add-locale.vue, template/tinyvue/src/views/menu/info/components/info-tab.vue
onMounted creates WebMcpServer, obtains injected serverTransport, registers tools (add-i18n-entry, add-menu) with Zod input schemas and handlers that drive component flows, then server.connect(serverTransport).
Menu component API
template/tinyvue/src/views/menu/info/components/add-menu.vue
Added public method setMenuInfo(data: Omit<CreateMenuDto,'id'>) to populate the form state programmatically.
Utils & styles
template/tinyvue/src/utils/base-utils.ts, template/tinyvue/src/assets/style/global.less
Added exported sleep(ms: number): Promise<void>; fixed missing CSS brace and added .tr-container { z-index: 999 !important; }.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant App as App.vue
    participant Client as WebMcpClient
    participant Transport as MessageChannelTransport
    participant Server as WebMcpServer (component)
    participant Component as Feature Component (locale/menu)

    User->>App: Mount
    App->>Transport: createMessageChannelPairTransport()
    App->>Client: new WebMcpClient(clientTransport)
    App->>Client: client.connect({agent:true, sessionId, url})
    App->>Component: provide(serverTransport)

    Component->>Server: onMounted -> new WebMcpServer()
    Server->>Server: registerTool(name, inputSchema, handler)
    Server->>Transport: server.connect(serverTransport)

    rect rgba(200,220,255,0.3)
      User->>Client: invoke remote tool (e.g., add-menu)
      Client->>Transport: send command
      Transport->>Server: route command
      Server->>Server: execute handler (interacts with Component state)
      Server-->>Transport: return result
      Transport-->>Client: deliver response
      Client-->>User: tool result
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped into App with a tiny remoter beat,
Tools sprout in components, inputs tidy and neat,
Transports pair like whiskers, session IDs in tow,
Sleep waits a moment, then remote actions flow,
A rabbit's little patch where menus and locales grow.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding @opentiny/next-sdk package and its integration throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kagol/add-opentiny-next-sdk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the enhancement New feature or request label Dec 31, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (5)
template/tinyvue/src/assets/style/global.less (1)

43-45: Consider whether !important is necessary.

The high z-index with !important ensures .tr-container appears on top, which is appropriate for overlays or agent UI components. However, !important can make future CSS adjustments more difficult. If the specificity can be managed through other means (e.g., more specific selectors or stacking context), that would be more maintainable.

template/tinyvue/src/utils/base-utils.ts (1)

12-14: LGTM! Simple and effective delay utility.

The sleep utility is correctly implemented and will be useful for orchestrating asynchronous MCP workflows. The function is imported and used in template/tinyvue/src/views/locale/components/add-locale.vue and template/tinyvue/src/views/menu/info/components/info-tab.vue.

Note: Consider adding a semicolon at the end of line 13 for consistency with the file's style (line 9 has a semicolon).

Optional: Add semicolon for consistency
 export const sleep = (ms: number): Promise<void> => {
-  return new Promise((resolve) => setTimeout(resolve, ms))
+  return new Promise((resolve) => setTimeout(resolve, ms));
 }
template/tinyvue/src/views/menu/info/components/add-menu.vue (1)

174-183: Consider simplifying property assignment.

The new setMenuInfo method assigns data fields to the reactive menuInfo object. The current implementation works correctly but is verbose. Consider using Object.assign for a more concise approach.

Simplified implementation
 setMenuInfo: (data: Omit<CreateMenuDto, 'id'>) => {
-  menuInfo.name = data.name;
-  menuInfo.path = data.path;
-  menuInfo.component = data.component;
-  menuInfo.icon = data.icon;
-  menuInfo.menuType = data.menuType;
-  menuInfo.parentId = data.parentId;
-  menuInfo.order = data.order;
-  menuInfo.locale = data.locale;
+  Object.assign(menuInfo, data);
 },
template/tinyvue/src/views/locale/components/add-locale.vue (1)

237-237: Consider using an enum for language IDs.

Line 237 defines the language ID as a union of literals (z.literal(1) and z.literal(2)). While functional, this approach makes the code less maintainable. Consider defining a language enum to improve readability and type safety.

Enum-based approach
// Add at the top of the file or in a shared types file
enum LanguageId {
  EN_US = 1,
  ZH_CN = 2
}

// Then use in schema:
lang: z.nativeEnum(LanguageId).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),

This makes the intent clearer and provides better IntelliSense support.

package.json (1)

34-38: Consider upgrading to the latest @modelcontextprotocol/sdk version or document the pinning rationale.

Version 1.16.0 exists on npm with no reported direct security vulnerabilities. However, it is significantly outdated—the latest stable release is 1.25.0 (Dec 15, 2025). If this older version is intentionally pinned for compatibility or other reasons, add a comment explaining the constraint. Additionally, run npm audit to check for vulnerabilities in transitive dependencies.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12f464b and 521b9e7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • package.json
  • template/tinyvue/package.json
  • template/tinyvue/src/App.vue
  • template/tinyvue/src/assets/style/global.less
  • template/tinyvue/src/utils/base-utils.ts
  • template/tinyvue/src/views/locale/components/add-locale.vue
  • template/tinyvue/src/views/menu/info/components/add-menu.vue
  • template/tinyvue/src/views/menu/info/components/info-tab.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e-test
🔇 Additional comments (2)
template/tinyvue/src/assets/style/global.less (1)

41-41: LGTM! Syntax fix applied correctly.

The missing closing brace for the .tiny-button block has been properly added.

template/tinyvue/src/App.vue (1)

9-26: LGTM! TinyRemoter configured appropriately.

The TinyRemoter component is properly configured with the agent root URL and menu item visibility controls. The reactive sessionId binding will enable dynamic session tracking.

Comment on lines 56 to 74
onMounted(async () => {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling and reconsider hard-coded sessionId.

The MCP client initialization has two concerns:

  1. Hard-coded sessionId on line 68 defeats the purpose of session management. The comment suggests this is for debugging with MCP Inspector, but production code should use dynamic session IDs. Consider using crypto.randomUUID() or making the fixed ID conditional based on an environment variable.

  2. Missing error handling: The async operations in onMounted lack try-catch blocks. If client.connect() fails, the error will be unhandled and sessionId.value will remain empty, potentially breaking the TinyRemoter integration.

Proposed fix with error handling and environment-based sessionId
 const sessionId = ref('')
 onMounted(async () => {
-  const [serverTransport, clientTransport] = createMessageChannelPairTransport()
-
-  provide('serverTransport', serverTransport)
-
-  // 创建 WebMcpClient ,并与 WebAgent 连接
-  const client = new WebMcpClient()
-  await client.connect(clientTransport)
-  const { sessionId: sessionID } = await client.connect({
-    agent: true,
-
-    // sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
-    sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
-
-    url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
-  })
-  sessionId.value = sessionID
-  console.log('sessionId:', sessionId.value)
+  try {
+    const [serverTransport, clientTransport] = createMessageChannelPairTransport()
+    
+    provide('serverTransport', serverTransport)
+    
+    const client = new WebMcpClient()
+    await client.connect(clientTransport)
+    
+    // Use fixed sessionId only in development for debugging
+    const fixedSessionId = import.meta.env.DEV 
+      ? 'd299a869-c674-4125-a84b-bb4e24079b99'
+      : crypto.randomUUID()
+    
+    const { sessionId: sessionID } = await client.connect({
+      agent: true,
+      sessionId: fixedSessionId,
+      url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
+    })
+    sessionId.value = sessionID
+    console.log('sessionId:', sessionId.value)
+  } catch (error) {
+    console.error('Failed to initialize MCP client:', error)
+    // Consider notifying the user or disabling MCP features
+  }
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
})
onMounted(async () => {
try {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
const client = new WebMcpClient()
await client.connect(clientTransport)
// Use fixed sessionId only in development for debugging
const fixedSessionId = import.meta.env.DEV
? 'd299a869-c674-4125-a84b-bb4e24079b99'
: crypto.randomUUID()
const { sessionId: sessionID } = await client.connect({
agent: true,
sessionId: fixedSessionId,
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
} catch (error) {
console.error('Failed to initialize MCP client:', error)
// Consider notifying the user or disabling MCP features
}
})
🤖 Prompt for AI Agents
In template/tinyvue/src/App.vue around lines 56 to 74, the onMounted block both
hard-codes a sessionId and lacks error handling; wrap the async client
creation/connect calls in a try-catch, log or surface errors, and ensure the
UI/state is updated only on success (e.g., set sessionId.value inside the try
and set an error state in the catch). Replace the fixed sessionId with a dynamic
value by default (use crypto.randomUUID()) and make the fixed ID conditional
(e.g., only use the hard-coded value when a debug flag or environment variable
is present) so production uses a generated UUID.

Comment on lines +222 to +253
onMounted(async () => {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
onOpen()
await sleep(1000)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(1000)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
}
)
await server.connect(serverTransport)
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if Transport type is exported from @opentiny/next-sdk
rg -nP "export.*Transport" node_modules/@opentiny/next-sdk -A 2

Repository: opentiny/tiny-pro

Length of output: 132


🏁 Script executed:

# Also check the actual file to verify it exists and code matches
if [ -f "template/tinyvue/src/views/locale/components/add-locale.vue" ]; then
  echo "=== File exists. Checking lines 222-253 ==="
  sed -n '222,253p' "template/tinyvue/src/views/locale/components/add-locale.vue"
else
  echo "File not found at template/tinyvue/src/views/locale/components/add-locale.vue"
  # Try to find it
  find . -name "add-locale.vue" -type f 2>/dev/null
fi

Repository: opentiny/tiny-pro

Length of output: 994


🏁 Script executed:

# Check if info-tab.vue exists and has similar MCP server setup pattern
find . -name "info-tab.vue" -type f 2>/dev/null | head -5

Repository: opentiny/tiny-pro

Length of output: 388


🏁 Script executed:

# Check if @opentiny/next-sdk is in package.json
cat package.json | grep -A 5 -B 5 "@opentiny/next-sdk"

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Check one info-tab.vue file to see similar MCP server pattern
head -n 400 "./template/tinyvue/src/views/menu/info/components/info-tab.vue" | grep -A 50 "onMounted"

Repository: opentiny/tiny-pro

Length of output: 3091


🏁 Script executed:

# Check package.json file itself for @opentiny/next-sdk and dependencies section
head -n 100 package.json | tail -n 50

Repository: opentiny/tiny-pro

Length of output: 2327


🏁 Script executed:

# Search for Transport type usage in the codebase
rg "Transport" --type vue --type ts --type js | head -20

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Search for Transport type usage more broadly
rg "Transport" --type ts --type js | head -20

Repository: opentiny/tiny-pro

Length of output: 880


🏁 Script executed:

# Check full package.json dependencies for @opentiny/next-sdk and related packages
rg "@opentiny" package.json

Repository: opentiny/tiny-pro

Length of output: 172


🏁 Script executed:

# Look for WebMcpServer import to understand where Transport might come from
rg "WebMcpServer|import.*Transport" -A 2 -B 2 | head -30

Repository: opentiny/tiny-pro

Length of output: 2406


🏁 Script executed:

# Check App.vue to see how serverTransport is typed and used
rg -A 10 "createMessageChannelPairTransport" "template/tinyvue/src/App.vue"

Repository: opentiny/tiny-pro

Length of output: 991


🏁 Script executed:

# Look for type definitions or interfaces related to Transport in the codebase
rg "type.*Transport|interface.*Transport" --type ts -A 3

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Check if there's a type definition file or declaration in node_modules or src
find . -name "*.d.ts" -o -name "*.ts" | xargs grep -l "Transport" 2>/dev/null | head -10

Repository: opentiny/tiny-pro

Length of output: 43


Add error handling and improve type safety.

The MCP server setup mirrors the pattern in info-tab.vue and has similar concerns:

  1. Type safety: Line 227 uses any for serverTransport. This should use a proper type instead of any.

  2. Hard-coded delays: Lines 242 and 246 use fixed 1000ms delays. Extract these as named constants.

  3. Missing error handling: No try-catch blocks around async operations. Both the tool handler (lines 240-248) and server connection (line 252) should handle potential errors.

  4. UI orchestration: The tool handler directly calls onOpen() and addLocale(), tightly coupling MCP logic to UI implementation.

These same issues appear in info-tab.vue (menu-management-mcp-server setup).

Proposed improvements
+const MCP_UI_DELAY = 1000; // ms
+
 onMounted(async () => {
+  try {
     const server = new WebMcpServer({
       name: 'i18n-management-mcp-server',
       version: '1.0.0'
     })
-    const serverTransport = inject<any>('serverTransport')
+    const serverTransport = inject('serverTransport')
+    if (!serverTransport) {
+      console.error('serverTransport not provided')
+      return
+    }

     server.registerTool(
       'add-i18n-entry',
       {
         title: '添加国际化词条',
         description: '添加国际化词条',
         inputSchema: {
           key: z.string().describe('词条关键字'),
           content: z.string().describe('词条内容'),
           lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
         }
       },
       async ({ key, content, lang }) => {
+        try {
           onOpen()
-          await sleep(1000)
+          await sleep(MCP_UI_DELAY)
           locale.key = key
           locale.content = content
           locale.lang = lang
-          await sleep(1000)
+          await sleep(MCP_UI_DELAY)
           addLocale()
           return { content: [{ type: 'text', text: `收到: ${key}` }] }
+        } catch (error) {
+          console.error('Failed to add i18n entry via MCP:', error)
+          return { 
+            content: [{ 
+              type: 'text', 
+              text: `添加词条失败: ${error instanceof Error ? error.message : String(error)}` 
+            }],
+            isError: true
+          }
+        }
       }
     )

     await server.connect(serverTransport)
+    console.log('i18n MCP server connected successfully')
+  } catch (error) {
+    console.error('Failed to initialize i18n MCP server:', error)
+  }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
onOpen()
await sleep(1000)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(1000)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
}
)
await server.connect(serverTransport)
});
const MCP_UI_DELAY = 1000; // ms
onMounted(async () => {
try {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject('serverTransport')
if (!serverTransport) {
console.error('serverTransport not provided')
return
}
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
try {
onOpen()
await sleep(MCP_UI_DELAY)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(MCP_UI_DELAY)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
} catch (error) {
console.error('Failed to add i18n entry via MCP:', error)
return {
content: [{
type: 'text',
text: `添加词条失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
}
}
}
)
await server.connect(serverTransport)
console.log('i18n MCP server connected successfully')
} catch (error) {
console.error('Failed to initialize i18n MCP server:', error)
}
});
🤖 Prompt for AI Agents
In template/tinyvue/src/views/locale/components/add-locale.vue around lines
222-253, replace the loosely-typed inject<any>('serverTransport') with the
correct transport type (use the MCP transport interface/type used elsewhere,
e.g., WebMcpTransport or the same type from info-tab.vue) to improve type
safety; extract the hard-coded 1000ms sleeps into named constants (e.g.,
HANDLER_DELAY_MS) at the top of the module and reference those constants; wrap
the async tool handler and the await server.connect(...) call in try-catch
blocks and log/return meaningful errors instead of letting exceptions bubble;
and decouple UI operations from the MCP handler by emitting an event or calling
a small adapter function that maps the handler result to UI actions
(onOpen/addLocale) so the handler does not directly call UI functions.

Comment on lines +246 to +255
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and view the relevant lines
if [ -f "template/tinyveo/src/views/menu/info/components/info-tab.vue" ]; then
  sed -n '246,255p' "template/tinyveo/src/views/menu/info/components/info-tab.vue"
else
  echo "Checking for correct file path..."
  find . -name "info-tab.vue" -type f 2>/dev/null | head -5
fi

Repository: opentiny/tiny-pro

Length of output: 178


🏁 Script executed:

# Check if @opentiny/next-sdk is in the project dependencies
find . -name "package.json" -type f | xargs grep -l "@opentiny/next-sdk" 2>/dev/null | head -5

Repository: opentiny/tiny-pro

Length of output: 92


🏁 Script executed:

# Check the node_modules for Transport type export from @opentiny/next-sdk
if [ -d "node_modules/@opentiny/next-sdk" ]; then
  echo "=== Checking for Transport type ==="
  find node_modules/@opentiny/next-sdk -name "*.d.ts" -o -name "*.ts" | xargs grep -l "export.*Transport" 2>/dev/null | head -5
else
  echo "@opentiny/next-sdk not found in node_modules"
fi

Repository: opentiny/tiny-pro

Length of output: 105


🏁 Script executed:

# View the file content at the specified lines
sed -n '240,260p' template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 525


🏁 Script executed:

# Search for Transport type definition in the codebase
rg "type.*Transport|export.*Transport" --type ts --type vue -i

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Check imports in the info-tab.vue file to understand what's already imported
head -30 template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 1117


🏁 Script executed:

# Check the package.json to see what version of @opentiny/next-sdk is used
rg "@opentiny/next-sdk" template/tinyvue/package.json -A 1 -B 1

Repository: opentiny/tiny-pro

Length of output: 170


🏁 Script executed:

# Search for all imports from @opentiny/next-sdk to see what types are available
rg "from ['\"]@opentiny/next-sdk['\"]" -A 3 -B 1

Repository: opentiny/tiny-pro

Length of output: 1562


🏁 Script executed:

# Search for Transport or transport-related types in the codebase
rg -i "transport" template/tinyvue/src/views/menu/info/components/info-tab.vue -B 2 -A 2

Repository: opentiny/tiny-pro

Length of output: 243


🏁 Script executed:

# Check if there are any type definitions or .d.ts files in the repo that might define Transport
find . -name "*.d.ts" -type f | xargs grep -l "Transport" 2>/dev/null | head -10

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Search for how serverTransport is actually used after injection
sed -n '255,280p' template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 880


🏁 Script executed:

# Check how createMessageChannelPairTransport is used in App.vue to understand transport types
sed -n '1,50p' template/tinyvue/src/App.vue | grep -A 10 "createMessageChannelPairTransport"

Repository: opentiny/tiny-pro

Length of output: 469


🏁 Script executed:

# Search for server.connect usage patterns
rg "server\.connect" -B 3 -A 3

Repository: opentiny/tiny-pro

Length of output: 1058


🏁 Script executed:

# Search for any transport-related type definitions or interfaces in the codebase
rg "transport" template/tinyvue/src -i --type ts --type vue | head -30

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Check if there's a web_search to verify what's exported from @opentiny/next-sdk
# We'll search the package documentation

Repository: opentiny/tiny-pro

Length of output: 43


🌐 Web query:

@opentiny/next-sdk Transport type export documentation

💡 Result:

You can import the Transport type from the package. Example:

import type { Transport } from '@opentiny/next-sdk'

(See the WebMcpClient connect signature which uses Transport in the OpenTiny NEXT docs.) [1]

Sources

  • OpenTiny NEXT — WebMcpClient (connect signature uses Transport). [1]

Replace any type for serverTransport with proper Transport type.

Line 255 uses any for the injected serverTransport, which bypasses TypeScript's type checking. Import the Transport type from @opentiny/next-sdk and apply it to maintain type safety.

Proposed fix
+import type { Transport } from '@opentiny/next-sdk'

 onMounted(async () => {
   // ...
   const server = new WebMcpServer({
     name: 'menu-management-mcp-server',
     version: '1.0.0'
   })
-  const serverTransport = inject<any>('serverTransport')
+  const serverTransport = inject<Transport>('serverTransport')
+  if (!serverTransport) {
+    console.error('serverTransport not provided')
+    return
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
import type { Transport } from '@opentiny/next-sdk'
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<Transport>('serverTransport')
if (!serverTransport) {
console.error('serverTransport not provided')
return
}
🤖 Prompt for AI Agents
In template/tinyvue/src/views/menu/info/components/info-tab.vue around lines 246
to 255, the injected serverTransport is typed as any which disables TypeScript
checks; import the Transport type from '@opentiny/next-sdk' (add: import type {
Transport } from '@opentiny/next-sdk') and replace
inject<any>('serverTransport') with inject<Transport>('serverTransport') (or
const serverTransport = inject<Transport>('serverTransport') || /* handle
undefined */) so the injected value is strongly typed and handle the possible
undefined return from inject.

Comment on lines +257 to +289
server.registerTool(
'add-menu',
{
title: '添加菜单',
description: '添加菜单',
inputSchema: {
name: z.string().describe('名称'),
order: z.number().describe('优先级').default(0),
parentId: z.number().describe('父菜单ID').optional(),
icon: z.string().describe('图标').optional().default(''),
component: z.string().describe('组件'),
path: z.string().describe('路径'),
locale: z.string().describe('国际化'),
}
},
async ({ name, order, parentId, icon, component, path, locale }) => {
handleAddMenu()
await sleep(1000)
addMenu.value.setMenuInfo({
name,
order,
parentId,
icon,
component,
menuType: "/",
path,
locale,
})
await sleep(1000)
onClickAdd()
return { content: [{ type: 'text', text: `收到: ${name}` }] }
}
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling and make delays configurable.

The MCP tool registration has several concerns:

  1. Hard-coded delays: Lines 274 and 285 use fixed 1000ms delays. These magic numbers make the code harder to maintain and test. Consider extracting them as named constants or making them configurable.

  2. Missing error handling: The tool handler lacks try-catch blocks. If handleAddMenu(), setMenuInfo(), or onClickAdd() fail, the error will propagate uncaught and the tool will return an incomplete response.

  3. UI orchestration in tool handler: The handler directly manipulates UI state (handleAddMenu(), onClickAdd()), which tightly couples the MCP tool to the component's internal implementation. This pattern may be difficult to test and maintain.

Proposed improvements
+const MCP_UI_DELAY = 1000; // ms - delay for UI updates to be visible
+
 onMounted(async () => {
   // ... server setup ...
   
   server.registerTool(
     'add-menu',
     {
       title: '添加菜单',
       description: '添加菜单',
       inputSchema: {
         name: z.string().describe('名称'),
         order: z.number().describe('优先级').default(0),
         parentId: z.number().describe('父菜单ID').optional(),
         icon: z.string().describe('图标').optional().default(''),
         component: z.string().describe('组件'),
         path: z.string().describe('路径'),
         locale: z.string().describe('国际化'),
       }
     },
     async ({ name, order, parentId, icon, component, path, locale }) => {
+      try {
         handleAddMenu()
-        await sleep(1000)
+        await sleep(MCP_UI_DELAY)
         addMenu.value.setMenuInfo({
           name,
           order,
           parentId,
           icon,
           component,
           menuType: "/",
           path,
           locale,
         })
-        await sleep(1000)
+        await sleep(MCP_UI_DELAY)
         onClickAdd()
         return { content: [{ type: 'text', text: `收到: ${name}` }] }
+      } catch (error) {
+        console.error('Failed to add menu via MCP:', error)
+        return { 
+          content: [{ 
+            type: 'text', 
+            text: `添加菜单失败: ${error instanceof Error ? error.message : String(error)}` 
+          }],
+          isError: true
+        }
+      }
     }
   )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
template/tinyvue/src/views/menu/info/components/info-tab.vue lines 257-289: the
MCP tool handler uses hard-coded 1000ms sleeps, has no error handling, and
directly manipulates component UI state; extract the delays into named constants
or a configurable prop (e.g., ADD_MENU_DELAY_MS) and replace literal 1000 with
that constant/prop, wrap the entire handler body in a try-catch that
logs/returns a clear error response on failure, and stop tightly coupling to
internal UI functions by emitting component events or calling injected callbacks
instead of directly invoking handleAddMenu() and onClickAdd() so the tool only
triggers abstracted actions and returns success/failure after setMenuInfo and
the delay complete.

}
)
await server.connect(serverTransport)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for server connection.

The server.connect() call on line 291 lacks error handling. If the connection fails, the MCP server won't be available and tools won't be accessible, but the component will continue functioning normally without any indication of the problem.

Add try-catch for server connection
-  await server.connect(serverTransport)
+  try {
+    await server.connect(serverTransport)
+    console.log('MCP server connected successfully')
+  } catch (error) {
+    console.error('Failed to connect MCP server:', error)
+    // Consider showing a user notification or disabling MCP features
+  }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await server.connect(serverTransport)
try {
await server.connect(serverTransport)
console.log('MCP server connected successfully')
} catch (error) {
console.error('Failed to connect MCP server:', error)
// Consider showing a user notification or disabling MCP features
}
🤖 Prompt for AI Agents
In template/tinyvue/src/views/menu/info/components/info-tab.vue around line 291,
the await server.connect(serverTransport) call lacks error handling; wrap the
connect call in a try-catch, catch and log the error (use existing logger or
console.error), update component state to reflect connection failure (e.g., set
a boolean like serverConnected = false or set an error message reactive
property), and surface a user-visible notification or disable dependent UI/tools
so users know the MCP server is unavailable.

@kagol
Copy link
Member Author

kagol commented Dec 31, 2025

@coderabbitai generate docstrings

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #166

coderabbitai bot added a commit that referenced this pull request Dec 31, 2025
Docstrings generation was requested by @kagol.

* #165 (comment)

The following files were modified:

* `template/tinyvue/src/utils/base-utils.ts`
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
template/tinyvue/package.json (1)

134-136: Update engines.node to >=18.0.0 to align with Vite 6.x requirements.

Vite 6.x requires Node.js 18 as the minimum; the current >=14.0.0 constraint is insufficient and can cause install failures if engineStrict is enabled. This also aligns with the broader OpenTiny ecosystem pattern (e.g., tiny-vue).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 521b9e7 and 7d89f1c.

📒 Files selected for processing (2)
  • package.json
  • template/tinyvue/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🪛 GitHub Actions: BackEnd UnitTest
template/tinyvue/package.json

[warning] 1-1: The field "resolutions" was found in /home/runner/work/tiny-pro/tiny-pro/template/tinyvue/package.json. This will not take effect. You should configure "resolutions" at the root of the workspace instead.

🪛 GitHub Actions: Playwright E2E Tests
template/tinyvue/package.json

[warning] 1-1: The field "resolutions" was found in package.json. This will not take effect under a workspace. Configure "resolutions" at the workspace root instead.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @template/tinyvue/src/App.vue:
- Around line 59-73: The onMounted block performing asynchronous MCP operations
(creating WebMcpClient and calling client.connect) lacks error handling; wrap
the async sequence starting at WebMcpClient instantiation and both
client.connect calls in a try/catch, only assign sessionId.value on success,
call process/UI-facing error reporting (e.g., console.error or a reactive error
state to show a message), and in the catch ensure the client is cleaned
up/closed if partially connected to avoid leaks; reference the onMounted
callback, WebMcpClient, client.connect, and sessionId for locating and applying
the fix.
- Around line 68-70: The hardcoded sessionId property (sessionId) in App.vue
should not be used in production because it can cause session collisions; change
the initialization so that in production it generates a unique id (e.g., via
crypto.randomUUID()), allow overriding via an environment/config variable, and
keep the hardcoded value only when running in development mode; update any call
that uses this value (the connect call that passes sessionId) to use the new
computed/configured sessionId instead.
- Around line 63-64: The code calls client.connect() twice (first with
clientTransport then with an options object), which violates
WebMcpClient.connect()’s contract; remove the duplicate first call and only call
client.connect with the ClientConnectOptions object (ensuring the transport is
passed via that options object if needed) so the single call returns the
sessionId used as sessionID.
🧹 Nitpick comments (1)
template/tinyvue/src/App.vue (1)

9-26: Consider extracting hardcoded configuration values.

The agent-root URL and menuItems configuration are hardcoded. For better maintainability and environment-specific deployments, consider moving these to a configuration file or environment variables.

♻️ Proposed refactor
+  const AGENT_ROOT_URL = import.meta.env.VITE_AGENT_ROOT_URL || 'https://agent.opentiny.design/api/v1/webmcp-trial/'
+  const HIDDEN_MENU_ITEMS = [
+    { action: 'qr-code', show: false },
+    { action: 'remote-control', show: false },
+    { action: 'remote-url', show: false }
+  ]

Then update the template:

   <tiny-remoter
-    agent-root="https://agent.opentiny.design/api/v1/webmcp-trial/"
+    :agent-root="AGENT_ROOT_URL"
     :session-id="sessionId"
-    :menuItems="[
-      {
-        action: 'qr-code',
-        show: false
-      },
-      {
-        action: 'remote-control',
-        show: false
-      },
-      {
-        action: 'remote-url',
-        show: false
-      }
-    ]"
+    :menuItems="HIDDEN_MENU_ITEMS"
   />
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d89f1c and 7686462.

📒 Files selected for processing (1)
  • template/tinyvue/src/App.vue
🔇 Additional comments (2)
template/tinyvue/src/App.vue (2)

30-37: LGTM! Clean import organization.

The new imports for MCP integration are well-organized and appropriate for the functionality being introduced.


55-57: LGTM! Clean transport setup.

The message channel pair transport creation and Vue provide pattern are correctly implemented.

Comment on lines +59 to +73
onMounted(async () => {
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
sessionId.value = sessionID
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for MCP connection failures.

The onMounted hook performs asynchronous MCP client operations without any error handling. If the connection fails, users will experience silent failures with no feedback.

🛡️ Proposed fix with error handling
   onMounted(async () => {
+    try {
+      // 创建 WebMcpClient ,并与 WebAgent 连接
+      const client = new WebMcpClient()
+      await client.connect(clientTransport)
+      const { sessionId: sessionID } = await client.connect({
+        agent: true,
+        // sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
+        sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
+        url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
+      })
+      sessionId.value = sessionID
+    } catch (error) {
+      console.error('Failed to initialize MCP client:', error)
+      // Consider showing user-facing error notification
+    }
-    // 创建 WebMcpClient ,并与 WebAgent 连接
-    const client = new WebMcpClient()
-    await client.connect(clientTransport)
-    const { sessionId: sessionID } = await client.connect({
-      agent: true,
-
-      // sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
-      sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
-
-      url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
-    })
-    sessionId.value = sessionID
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
sessionId.value = sessionID
})
onMounted(async () => {
try {
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
sessionId.value = sessionID
} catch (error) {
console.error('Failed to initialize MCP client:', error)
// Consider showing user-facing error notification
}
})
🤖 Prompt for AI Agents
In @template/tinyvue/src/App.vue around lines 59 - 73, The onMounted block
performing asynchronous MCP operations (creating WebMcpClient and calling
client.connect) lacks error handling; wrap the async sequence starting at
WebMcpClient instantiation and both client.connect calls in a try/catch, only
assign sessionId.value on success, call process/UI-facing error reporting (e.g.,
console.error or a reactive error state to show a message), and in the catch
ensure the client is cleaned up/closed if partially connected to avoid leaks;
reference the onMounted callback, WebMcpClient, client.connect, and sessionId
for locating and applying the fix.

Comment on lines +63 to +64
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

@opentiny/next-sdk WebMcpClient connect method API documentation

💡 Result:

Summary of WebMcpClient.connect (from @opentiny/next-sdk):

  • Signature: async connect(options: Transport | ClientConnectOptions): Promise<{ transport: Transport; sessionId: string }>. [1]
  • Options: can pass a Transport directly or an object with:
    • url: string (agent service URL)
    • token?: string
    • sessionId?: string
    • type?: 'channel' | 'sse'
    • agent?: boolean (connect to WebAgent)
    • onError?: (error: Error) => void. [1]
  • Returns: { transport, sessionId }. [1]
  • Examples: connecting with a MessageChannel transport, connecting to a remote WebAgent (streamable HTTP by default) or using SSE via type: 'sse', and passing sessionId or onError callbacks. [1][2]

Sources:
[1] OpenTiny NEXT docs — WebMcpClient class (connect).
[2] @opentiny/next-sdk package info / examples (npm / community guides).


Remove the duplicate client.connect() call on line 63.

The WebMcpClient.connect() method accepts either a Transport directly or a ClientConnectOptions object—not both sequentially. The current code calls connect() twice, which violates the API contract. Keep only line 64's call with the options object, or refactor to pass the transport through the options object if needed.

🤖 Prompt for AI Agents
In @template/tinyvue/src/App.vue around lines 63 - 64, The code calls
client.connect() twice (first with clientTransport then with an options object),
which violates WebMcpClient.connect()’s contract; remove the duplicate first
call and only call client.connect with the ClientConnectOptions object (ensuring
the transport is passed via that options object if needed) so the single call
returns the sessionId used as sessionID.

Comment on lines +68 to +70
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider removing hardcoded sessionId for production.

The hardcoded sessionId on line 68 is noted as being for debugging convenience with MCP Inspector. However, using a fixed session identifier could cause conflicts when multiple users or browser tabs attempt to use the same session simultaneously, leading to unpredictable behavior.

Consider:

  • Using crypto.randomUUID() (as mentioned in the comment) for production
  • Making this configurable via environment variable
  • Only using the hardcoded value in development mode
♻️ Proposed fix
+  const MCP_URL = import.meta.env.VITE_MCP_URL || 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
+  const DEBUG_SESSION_ID = import.meta.env.DEV ? 'd299a869-c674-4125-a84b-bb4e24079b99' : crypto.randomUUID()

Then update the connect call:

       const { sessionId: sessionID } = await client.connect({
         agent: true,
-        // sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
-        sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
-        url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
+        sessionId: DEBUG_SESSION_ID,
+        url: MCP_URL
       })

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @template/tinyvue/src/App.vue around lines 68 - 70, The hardcoded sessionId
property (sessionId) in App.vue should not be used in production because it can
cause session collisions; change the initialization so that in production it
generates a unique id (e.g., via crypto.randomUUID()), allow overriding via an
environment/config variable, and keep the hardcoded value only when running in
development mode; update any call that uses this value (the connect call that
passes sessionId) to use the new computed/configured sessionId instead.

@kagol kagol merged commit 062fa4d into dev Jan 9, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants